require 'chipmunk_object'
require 'photon'

class Float
	def deg2unit_vect
		CP::Vec2.for_angle(self*Math::PI/180.0)
	end
end

AS.open_screen(640, 480, :vbl_sync => false)
Width, Height = AS.screen_w, AS.screen_h
ScreenBB = CP::BB.new(-30, -30, Width + 30, Height + 30)

class AeroidSprite < Photon::Node::Matrix
	attr_accessor :pos, :angle, :scale
	
	def initialize(template, v, rotation)
		@matrix = Photon::Matrix.new
		super(GL::MODELVIEW, @matrix, template)
		@v, @rotation = v, rotation
		@pos = vec2(0,0)
		@angle = 0.0
		@scale = 1.0
 	end
 	
	def update
		self.angle += @rotation
		self.pos = ScreenBB.wrap_vect(pos + @v)
 		@matrix.reset!.sprite!(@pos.x, @pos.y, @scale, @scale, @angle/180.0*Math::PI)
 	end
end

class Bullet < AeroidSprite
	Template = Photon::Node::SpriteTemplate.new(Photon::Texture::Rect.new('gfx/bullet.png'), 5, 5)
	
	def initialize(p, vel)
		super(Template, vel, 0.0)
		self.pos = p
	end
end

class Player < AeroidSprite
	Template = Photon::Node::SpriteTemplate.new(Photon::Texture::Rect.new('gfx/ship.png'), 14, 14)
	
	BangSound = AS::SoundPlayer.new(AS::Sound.new('sfx/hit1.ogg'))
	BangSound.volume = 0.5
	
	def initialize
		super(Template, vec2(0,0), 0.0)
		self.pos = vec2(Width/2.0, Height/2.0)
	end
	
	def reset!
		initialize
	end
	
	def update(input_pad)
		@v += self.angle.deg2unit_vect*(input_pad[:thrust]*0.1)
		@v = @v.normalize*3.0 if @v.dot(@v) > 9.0

		super()
		self.angle += input_pad[:turn]*3.0
	end
	
	def fire
		BangSound.play
		Bullet.new(self.pos, angle.deg2unit_vect*10.0)
  end
end

class Asteroid < AeroidSprite
	Template = Photon::Node::SpriteTemplate.new(Photon::Texture::Rect.new('gfx/asteroid.png'), 26, 22)
	
	def initialize(p = nil, size = 1.0)
		super(Template, vec2(rand - 0.5, rand - 0.5), rand*2.0 - 1.0)
		self.pos = p ? p : vec2(rand*AS.screen_w,rand*AS.screen_h)
		
		self.scale = size
	end
end

class AeroidsGameStateDelegate
	BoomSound = AS::SoundPlayer.new(AS::Sound.new('sfx/hit3.ogg'))
	BoomSound.volume = 0.25
	
	def initialize
		super
		
		@actions = AS::Event::ActionListener.new
		@actions.action(AS::Event.source_for_key(:Key_ESCAPE)){|event| AS::GameState.stop unless event.state}
		
		@input_pad = AS::Event::InputPad.new
		@input_pad.kaxis(:thrust, :Key_DOWN, :Key_UP)
		@input_pad.kaxis(:turn, :Key_RIGHT, :Key_LEFT)
		@input_pad.key(:fire, :Key_SPACE){|pressed| @bullets << @player.fire if pressed}
		
		@scene = Photon::Node::RenderState.construct({:blend => Photon::Blend::PremultAlpha}){
			Photon::Node::Array.new [
				@player = Player.new,
				Photon::Node::Array.construct{@bullets = []},
				Photon::Node::Array.construct{@steroids = []},
			]
		}
		
		@fps = AS::FPSCounter.new(30)
	end
	
	def input(event)
		@actions.call(event)
		@input_pad.call(event)
	end
	
	def asteroid_impact(pos, radius)
		@steroids.each do|rock|
			if rock.pos.near?(pos, 22.0*rock.scale + radius)
				@steroids.delete(rock)
				2.times{@steroids << Asteroid.new(rock.pos, rock.scale/2.0)} if rock.scale > 0.25
				BoomSound.play
				return true
			end
		end
		return false
	end
	
	def update
		puts @fps if @fps.tick

		@player.update(@input_pad)
		@bullets.send_each(:update)
		@steroids.send_each(:update)

		@player.reset! if asteroid_impact(@player.pos, 14.0)
		@bullets.delete_if{|bullet| asteroid_impact(bullet.pos, 4.0)}
		10.times{@steroids << Asteroid.new} if @steroids.empty?
	end
	
	def draw
		AS.clear_screen
    
		@scene.render
	end
end

music = AS::Music.new('sfx/music.ogg', true)
music.play

class SimpleState < AS::GameState
	attr_reader :needs_update
	
	def initialize(delegate)
		super(delegate)
		
		@needs_update = true
	end
	
	def update
		@needs_update = false
		super
	end
	
	def draw
		@needs_update = true
		super
	end
end


#SimpleState.new(AeroidsGameStateDelegate.new).run
AS::GameState::TickLimitedState.new(1.0/60.0, AeroidsGameStateDelegate.new).run
